<template>
  <Top-Page>
    <view class="select-collect-wrap" v-show="choiceCollectShow">
      <view class="select-collect-btn__text" @tap="changeChoiceCollectShow">取消</view>
      <view class="select-collect-btn__text" @tap="forwardMsg(2)">转发</view>
      <view class="select-collect-btn__text" @tap="removeMessage(2)">删除</view>
      <view class="select-collect-btn__text" @tap="collectMsg(2)">收藏</view>
    </view>
    <!-- #ifdef APP -->
    <movable-area class="movable-area-box">
      <movable-view
        v-if="contact.live_info"
        class="movable-view-box"
        :x="x"
        :y="y"
        direction="all"
        @change="onChange"
        @click="toLives"
      >
        <view>去看</view>
        <view>直播</view>
      </movable-view>
    </movable-area>
    <!-- #endif -->
    <cu-custom
      :bgColor="[
        'bg-white',
        {
          'novice-guide-location-2': false,
        },
      ]"
      :isBack="true"
      class="cu-header"
    >
      <template #backText></template>

      <template #content>
        <view
          style="color: #050f1b"
          class="im-flex im-justify-content-center im-align-items-center"
          @click.stop="contact.userinfo.length > 2 && (changeInfoShow = !changeInfoShow)"
        >
          <Tags v-if="is_group == 1" text="群聊" size="mini" />
          <Tags v-if="is_group != 1 && (query.type === 'casual' || contact.tempChat)" text="临时聊天" size="mini" />
          <statusPoint
            v-if="is_group == 0 && contact.is_online == 1 && globalConfig.chatInfo?.online == 1"
            type="success"
          ></statusPoint>
          <text class="text-overflow" v-if="is_group == 1">
            {{ contact.displayName }}
          </text>
          <text class="text-overflow" v-if="is_group == 1">({{ contact.num }})</text>
          <text class="text-overflow" v-if="is_group != 1 && query.type === 'casual'">
            {{ query.realname }}
          </text>
          <view class="text-overflow item-level__wrap" v-if="is_group != 1 && query.type != 'casual'">
            <template v-if="contact.userinfo.length">
              {{ contact.userinfo[changeInfoNum].realname }}
            </template>
            <image
              v-if="contact.userinfo?.length > 2"
              class="h-32 w-32"
              src="/static/image/common/chat-r.png"
              mode="heightFix"
            ></image>
            <!-- <image class="level-icon" v-if="contact.level?.icon" :src="contact.level.icon" mode="widthFix" /> -->
            <!-- <view class="level-icon-wrap" v-if="contact.level?.icon">
              <image class="level-icon" :src="contact.level?.icon" mode="widthFix" />
              {{ contact.level?.name }}
            </view> -->
          </view>
        </view>
      </template>
      <template #right v-if="contact.identity != 1">
        <view :class="['cuIcon-more', 'mr-10', 'f-16']" @tap="openDetails"></view>
      </template>
    </cu-custom>
    <scroll-view
      class="scroll-wrap"
      ref="scrollView"
      scroll-y="true"
      :scroll-anchoring="true"
      :scroll-top="scrollTop"
      @scroll="scrollChat"
      @scrolltoupper="scrolltoupper"
      @click.stop="instructOnClice($event)"
      :scroll-into-view="scrollIntoView"
      :style="[
        {
          /*height: scrollH + 'rpx',*/ position: 'fixed',
          top: navBarHeight + paddingT + 'rpx',
          bottom: bottomHeight + 'px',
        },
        contact.chat_bg
          ? `background:url(${contact.chat_bg}) no-repeat fixed;background-size: cover;`
          : `background-color: #efefef;`,
      ]"
    >
      <!--  v-if="is_silent == 0" -->
      <view class="cu-chat" :style="{ paddingBottom: paddingB + assignPB + 'px' }" @click="closeInput" id="more-oprate">
        <uni-load-more :contentText="{ contentnomore: ' ' }" :status="loading"></uni-load-more>
        <template v-for="(item, index) in messageList" :key="index" :id="'chatItem_' + index">
          <!-- <template v-if="!item.destruction && sex == item.sex && is_group != 1"> -->
          <template v-if="conditionShow(item.destruction, item.sex, item.age_min, item.age_max, item.fromUser.user_id)">
            <view class="cu-info" v-if="item.type == 'event'">
              {{ item.content }}
              <text
                class="c-primary"
                v-if="item.is_undo == 1 && getTime() - item.sendTime < 120000"
                @tap="reEdit(item.oldContent ?? '')"
              >
                重新编辑
              </text>
            </view>
            <template v-else>
              <checkbox-group :key="'message-list'" :id="`msg_${item.id}`">
                <view
                  class="cu-item"
                  :class="[item.fromUser.id == user.user_id ? 'im-rows-reverse self im-justify-content-start' : '']"
                >
                  <!-- 多选的收藏 -->
                  <checkbox
                    class="collect-checkbox"
                    v-show="choiceCollectShow"
                    :checked="item.checked"
                    @click="checkboxChange(item)"
                  />

                  <!-- 本人的信息 -->
                  <im-user
                    v-if="!item.cut"
                    :info="item.fromUser"
                    :is_group="contact.id"
                    :profile="isProfile"
                    :self="true"
                  ></im-user>
                  <im-user
                    v-else
                    :info="contact.userinfo"
                    :profile="isProfile"
                    :self="false"
                    :cut="!!item.cut"
                    :changeInfoNum="changeInfoNum || contact.usernum"
                    :is_group="contact.id"
                  ></im-user>

                  <view
                    class="main im-wrap"
                    @touchstart="moreOption(item)"
                    @touchend="endTimer"
                    @click.stop="dblclick(item)"
                    @contextmenu.prevent="handleRightClick(item, $event)"
                  >
                    <view
                      class="f-12 c-666 item-level__wrap"
                      style="width: 100%; margin-bottom: 6rpx"
                      v-if="is_group == 1 && item.fromUser.id != user.user_id"
                    >
                      {{ item.fromUser.realname }}
                      <image
                        v-if="item.fromUser?.level?.icon"
                        class="level-icon__1"
                        :src="item.fromUser?.level?.icon"
                        mode="widthFix"
                      ></image>
                    </view>

                    <!-- 文字消息 -->
                    <view
                      class="content shadow"
                      :class="[item.fromUser.id == user.user_id ? 'bg-green' : '']"
                      v-if="item.type == 'text'"
                    >
                      <mp-html
                        class="mp-html"
                        container-style="overflow: hidden;display:inline;white-space: pre-wrap"
                        :content="emojiToHtml(item.content)"
                      />
                    </view>

                    <!-- 名片 -->
                    <view
                      class="content shadow user-card"
                      :class="[item.fromUser.id == user.user_id ? 'bg-green' : '']"
                      v-else-if="item.type == 'usercard'"
                      @click="openUserDetail(item.content.user_id)"
                    >
                      <view class="card-top">
                        <image class="card-avatar" :src="item.content.avatar" />
                        <view class="card-realname">
                          {{ item.content.realname }}
                        </view>
                      </view>
                      <view class="card-bottom">个人名片</view>
                    </view>

                    <!-- 定位 -->
                    <view
                      class="content shadow user-location"
                      :class="[item.fromUser.id == user.user_id ? 'bg-green' : '']"
                      v-else-if="item.type == 'location'"
                      @click.stop="openGetLocation(item.content.lng, item.content.lat)"
                    >
                      <view class="user-location-top">
                        <view class="user-location-address text-one">{{ item.content.address }}</view>
                        <view class="user-location-township">{{ item.content.township }}</view>
                      </view>
                      <image
                        :src="`https://restapi.amap.com/v3/staticmap?location=${item.content.lng},${item.content.lat}&zoom=10&size=350*300&markers=mid,,A:${item.content.lng},${item.content.lat}&key=b05d44fdf8af776e042240c377c10b1d`"
                        mode=""
                      ></image>
                    </view>

                    <!-- 接龙信息 -->
                    <view
                      class="content shadow user-relay"
                      :class="[item.fromUser.id == user.user_id ? 'bg-green' : '']"
                      v-else-if="item.type == 'connectdragon'"
                    >
                      <view class="user-relay__title">
                        {{ item.content.title || "接龙" }}
                      </view>

                      <view class="user-relay__list" v-if="item.content.data && item.content.data.length">
                        <view class="user-relay__list-item" v-for="(it, ind) in item.content.data" :key="it">
                          {{ ind + 1 }}. {{ it }}
                        </view>
                      </view>

                      <view class="user-relay__desc" v-if="item.content.desc">
                        {{ item.content.desc }}
                      </view>

                      <view
                        v-if="item.content.keep == 1"
                        class="user-relay__join"
                        @click.stop="joinRelay(item.content)"
                      >
                        参与接龙
                      </view>
                    </view>

                    <!-- 图片消息 -->
                    <image
                      v-else-if="item.type == 'image'"
                      :src="item.content"
                      class="radius-4"
                      style="width: 7.5rem"
                      mode="widthFix"
                      @tap="showImgs"
                      :data-img="item.content"
                    ></image>

                    <image
                      v-else-if="item.type == 'emoji-image'"
                      :src="item.content"
                      class="radius-4"
                      style="width: 7.5rem"
                      mode="widthFix"
                      :data-img="item.content"
                    ></image>
                    <!-- 语音消息 -->
                    <view
                      v-else-if="item.type == 'voice'"
                      class="im-voice-msg im-flex im-rows im-nowrap im-align-items-center radius-20"
                      :class="[
                        index == playIndex ? 'linear-green' : '',
                        item.fromUser.id == user.user_id ? 'im-rows-reverse' : '',
                      ]"
                      :data-voice="item.content"
                      :data-index="index"
                      @tap="playVoice($event, index)"
                    >
                      <!-- :style="{ width: item.extends.duration * 3 + 'px' }" -->
                      <text
                        class="f-16 cuIcon-subscription rotate45"
                        :class="[
                          index == playIndex ? 'c-white' : '',
                          item.fromUser.id == user.user_id ? 'rotate225' : '',
                        ]"
                      ></text>
                      <view class="im-voice-msg-text" :class="[index == playIndex ? 'c-white' : '']">
                        <span class="extends-duration">{{ item.extends.duration }} "</span>
                        <span class="play-time" v-if="item.extends.currentTime">/ {{ item.extends.currentTime }}</span>
                      </view>
                    </view>
                    <!-- 视频消息 -->
                    <view v-else-if="item.type == 'video'">
                      <view class="course-video radius-10" @tap="handlePlay(item)">
                        <!-- 播放弹层 -->
                        <view class="relative-shadow">
                          <view class="cuIcon-video icon-center f-28 c-white"></view>
                        </view>
                        <image :src="item.extends.poster" class="" mode="heightFix"></image>
                      </view>
                    </view>
                    <!-- 文件消息 -->
                    <view v-else-if="item.type == 'file'">
                      <view
                        class="file-card bg-white radius-10 im-flex im-justify-content-start pd-10 im-align-items-center"
                        @tap="preview(item)"
                      >
                        <view class="file-icon cuIcon-text f-36"></view>
                        <view class="im-flex im-columns ml-10">
                          <view class="text-overflow file-name">{{ item.fileName }}</view>
                          <view class="text-gray file-size f-12">{{ fileSize(item.fileSize) }}</view>
                        </view>
                      </view>
                    </view>
                    <!-- 音视频消息 -->
                    <view
                      v-else-if="item.type == 'webrtc'"
                      @tap="calling(item.extends.type)"
                      class="im-voice-msg im-flex im-rows im-nowrap im-align-items-center radius-20"
                      :class="[item.fromUser.id == user.user_id ? 'im-rows-reverse' : '']"
                    >
                      <text
                        class="f-16"
                        :class="[
                          item.extends.type == 1 ? 'cuIcon-record' : 'cuIcon-dianhua',
                          item.fromUser.id == user.user_id ? 'rotate180' : '',
                        ]"
                      ></text>
                      <text class="im-voice-msg-text">{{ item.content }}</text>
                    </view>
                    <!-- 其他消息 -->
                    <imItem v-else :item="item" :index="index" :isSelf="true"></imItem>

                    <view class="item-quote-wrap" v-if="item.quote" @click="quotePreview(item.quote)">
                      {{ item.quote.name }}:{{ item.quote.content }}
                    </view>
                  </view>
                  <view class="mt-10 f-20" v-if="item.fromUser.id == user.user_id">
                    <view class="cuIcon-icloading icon-spin c-999" v-if="item.status == 'going'"></view>
                    <view class="cuIcon-infofill c-red" v-if="item.status == 'failed'" @tap="reSend(item)"></view>
                  </view>

                  <view class="date">
                    <text
                      v-if="item.is_group == 0 && item.fromUser.id == user.user_id"
                      :class="item.is_read ? 'c-success' : 'c-gray'"
                    >
                      {{ item.is_read ? "已读" : "未读" }}
                    </text>
                    <!-- {{ sendTime(item.sendTime) }} -->
                  </view>
                  <view v-if="item.is_secret == 1" class="mi-liao mark-wrap">密</view>
                  <!-- <view v-if="!!item.age_max" @tap="changeSppointDetailShow(index)" class="appoint-wrap"> -->
                  <view v-if="!!item.age_max" @tap="item.appointDetail = !!!item.appointDetail" class="appoint-wrap">
                    <view class="mark-wrap">指定人可见</view>
                    <view class="appoint-detail" v-if="!!item.appointDetail">
                      <view class="appoint-detail-li">
                        <view class="appoint-detail-decoration">·</view>
                        <view>{{ item.sex == 0 ? "女" : item.sex == 1 ? "男" : "未知" }}</view>
                      </view>
                      <view class="appoint-detail-li">
                        <view class="appoint-detail-decoration">·</view>
                        <view>{{ item.age_min }}至{{ item.age_max }}岁</view>
                      </view>
                    </view>
                  </view>
                  <view
                    class="appoint-detail-overlay"
                    v-show="!!item.appointDetail"
                    @tap="item.appointDetail = !item.appointDetail"
                  ></view>
                </view>
              </checkbox-group>
            </template>
          </template>
        </template>
        <view v-if="videoModel" class="video-model im-flex im-align-items-center">
          <view class="c-white radius-16 close-model" @tap="closeModel">关闭</view>
          <video class="video-box" id="myVideo" :src="videoUrl" controls autoplay="autoplay"></video>
        </view>
      </view>
    </scroll-view>
    <view id="im-input">
      <imInput
        v-if="contact.banned != 2"
        @send="sendMessage"
        @isSilent="isSilent"
        @setPad="setPad"
        @assignShowPB="assignShowPB"
        :boxStatus="boxStatus"
        :contact="contact"
        :query="query"
        v-model:curMsg="curMsg"
        ref="imInput"
      ></imInput>
      <view v-else class="banned-chat">禁言中，当前不可参与群聊</view>
    </view>
    <view class="cu-modal bottom-modal" :class="modelName == 'moreOpt' ? 'show' : ''" @click="modelName = ''">
      <view class="cu-dialog">
        <view class="manage-content">
          <view class="cu-list menu bg-white">
            <view
              class="cu-item"
              @tap="undoMsg()"
              v-if="(getTime() - curMsg.sendTime < 120000 && curMsg.fromUser.id == user.user_id) || contact.role < 3"
            >
              <view class="content padding-tb-sm">
                <text class="cuIcon-repeal"></text>
                <text>撤回消息</text>
              </view>
            </view>

            <view class="cu-item" @tap="copyMsg()">
              <view class="content padding-tb-sm">
                <text class="cuIcon-copy"></text>
                <text>复制{{ copyTxt }}</text>
              </view>
            </view>

            <view class="cu-item" @tap="compileImg()" v-if="curMsg.type === 'image'">
              <view class="content padding-tb-sm">
                <text class="cuIcon-fork"></text>
                <text>编辑图片</text>
              </view>
            </view>

            <!-- v-if="curMsg.type != 'voice'" -->
            <view class="cu-item" @tap="forwardMsg(1)">
              <view class="content padding-tb-sm padding-tb-sm-2">
                <text class="cuIcon-forward"></text>
                <text>转发</text>
              </view>
            </view>

            <!-- v-if="curMsg.type != 'voice'" -->
            <view class="cu-item" @tap="collectMsg(1)">
              <view class="content padding-tb-sm padding-tb-sm-2">
                <image class="icon-png-2" mode="widthFix" src="../../static/image/message/collect.png" />
                <!-- <text class="cuIcon-forward"></text> -->
                <text>收藏</text>
              </view>
            </view>

            <view class="cu-item" @tap="removeMessage(1)">
              <view class="content padding-tb-sm padding-tb-sm-2">
                <image class="icon-png-2" mode="widthFix" src="../../static/image/cancel.png" />
                <text>删除</text>
              </view>
            </view>

            <view class="cu-item" @tap="quote()">
              <view class="content padding-tb-sm padding-tb-sm-2">
                <image class="icon-png-2" mode="widthFix" src="../../static/image/cancel.png" />
                <text>引用</text>
              </view>
            </view>

            <view class="cu-item" @tap="choiceMsg()" v-if="curMsg.type != 'voice'">
              <view class="content padding-tb-sm">
                <image class="icon-png-2" mode="widthFix" src="../../static/image/message/choice.png" />
                <!-- <text class="cuIcon-forward"></text> -->
                <text>多选</text>
              </view>
            </view>

            <view class="parting-line-5"></view>
            <view class="cu-item" @click="modelName = ''">
              <view class="content padding-tb-sm">
                <text class="c-red">取消</text>
              </view>
            </view>
          </view>
        </view>
      </view>
    </view>
    <!--  -->
    <!-- v-if="modelName == 'musicPlay'" -->
    <view class="cu-modal bottom-modal" :class="modelName == 'musicPlay' ? 'show' : ''" @click="closeMusic()">
      <view class="cu-dialog" @tap.stop="">
        <view class="pd-20">
          <sy-audio
            ref="audio"
            :src="curMsg.content"
            audioCover=""
            subheading=""
            :audioTitle="curMsg.fileName"
            :key="curMsg.id"
          ></sy-audio>
        </view>
        <view class="cu-list menu bg-white">
          <view class="cu-item" @tap="closeMusic()">
            <view class="content padding-tb-sm">
              <text>关闭</text>
            </view>
          </view>
        </view>
      </view>
    </view>
    <view class="cu-modal bottom-modal" :class="modelName == 'copyModel' ? 'show' : ''">
      <view class="cu-dialog">
        <view class="cu-bar bg-white">
          <view class="action text-gray" @click="modelName = ''">取消</view>
          <view class="action text-green" @click="copyMsg()">复制</view>
        </view>
        <scroll-view scroll-y="true" :style="{ height: scrollH + 'rpx' }">
          <view class="pd-20 text-container">
            <mp-html :content="curMsg.content"></mp-html>
          </view>
        </scroll-view>
      </view>
    </view>
    <!-- <view class="appoint-detail-overlay" v-show="appointDetailShow" @tap="changeSppointDetailShow(-1)"></view> -->
    <view class="ate-tag" @click="gotoATe" v-if="ateObj.show">@信息</view>
    <Popup
      v-model:show="changeInfoShow"
      position="top"
      :top="CustomBar"
      class="change-user-info-popup"
      overlayClass="user-info-overlay"
    >
      <template v-for="(item, index) in contact.userinfo">
        <!--  @click="(changeInfoNum = index), (changeInfoShow = false)" -->
        <view v-if="index > 0" @click="changeInfo(index)" class="change-user-info-item border-bottom-after">
          <image class="change-user-info-avatar" :src="item.avatar" mode="aspectFill" />
          <view class="change-user-info-realname">{{ item.realname }}</view>
        </view>
      </template>
    </Popup>

    <view v-if="showModalDialog" class="l-dialog-overlay"></view>
    <view v-if="showModalDialog" class="l-dialog">
      <view class="l-dialog-title">删除{{ modalsStatus === 1 ? "联系人和" : "" }}聊天记录</view>

      <view class="l-dialog-content">确认是否删除{{ modalsStatus === 1 ? "当前联系人和" : "" }} 聊天记录？</view>

      <view class="l-dialog-btns">
        <view class="l-dialog-btn l-dialog-btn__confirm" @click="lModalConfirm">确定</view>
        <view class="l-dialog-btn l-dialog-btn__cancel" @click="lModalCancel">取消</view>
      </view>
    </view>

    <chj-imgEdit ref="chjImgEdit" @confirm="chjConfirm" @cancel="chjCancel" />
  </Top-Page>
</template>

<script>
// const innerAudioContext = uni.createInnerAudioContext();
import imInput from "@/components/message/im-input.vue";
import imItem from "@/components/message/im-item.vue";
import Popups from "@/components/Popups/index.vue";
import statusPoint from "@/components/status.vue";
import imUser from "@/components/im-user.vue";
import emoji from "@/utils/emoji.js";
import { useloginStore } from "@/store/login";
import { useMsgStore } from "@/store/message";
import { storeToRefs } from "pinia";
import pinia from "@/store/index";

const msgStore = useMsgStore(pinia);
const { newMessage, msgList, getContact, appendMsg, checkMsg } = storeToRefs(msgStore);
const userStore = useloginStore(pinia);
import { useFriendStore } from "@/store/friend.js";
import { navBack } from "@/utils/utils.js";
import { uploadFiles } from "@/utils/fileUtils.js";
const friendStore = useFriendStore(pinia);
const getTime = () => {
  return new Date().getTime();
};
import Popup from "@/components/Popup/Popup.vue";
export default {
  components: {
    imInput,
    imItem,
    imUser,
    statusPoint,
    Popup,
    Popups,
  },
  data() {
    return {
      navBack,
      scrollIntoView: "",
      ateObj: {
        show: false,
        id: "",
      },
      footerHeight: "50px",
      modalsStatus: -1,
      showModalDialog: false,
      x: 0,
      y: 100,
      CustomBar: this.CustomBar,
      userID: "",
      noviceGuide: uni.getStorageSync("noviceGuide") || [],
      changeInfoShow: false,
      changeInfoNum: 0,
      query: {},
      innerAudioContext: uni.createInnerAudioContext({ obeyMuteSwitch: false }),
      itemInd: -1,
      appointDetailIndex: 0,
      appointDetailShow: false,
      //沉默
      is_silent: 0,
      //当前时间
      time: new Date().getTime(),
      //年龄
      age: 0,
      sex: "",
      //阅后即焚
      queueList: [],
      destructionMsgTimer: null,
      destructionTime: 60 * 1000 * 5, //5分钟
      delayTime: 1 * 1000,
      //多选收藏
      choiceCollectShow: false,
      user: userStore.userInfo,
      contact: {},
      is_group: 0,
      boxStatus: 0,
      paddingT: 0,
      video: "",
      videoUrl: "",
      videoModel: false,
      InputBottom: 0,
      player: null,
      playIndex: -1,
      emojiMap: [],
      fileExt: [],
      page: 1,
      limit: 20,
      moreData: true, //是否有更多数据
      newMessage: newMessage,
      messageList: msgList,
      newheight: 0,
      scrollTop: 0,
      loading: "more",
      loadLock: false,
      scrollHeight: 0,
      paddingB: 0,
      assignPB: 0,
      contact_id: 0,
      bottomHeight: 50,
      globalConfig: userStore.globalConfig,
      userInfo: userStore.userInfo,
      modelName: "",
      curMsg: "",
      isSending: false,
      copyTxt: "文本",
      wsData: null,
      timer: null,
      clickCount: 0,
      clickTimeout: null,
      isProfile: false,
      collectList: [], //收藏的消息列表
      historyMsgData: {},
      lastTapDiffTime: 0,
      screenWidth: 0,
      screenHeight: 0,
      lastZone: 0, //点击的区域
    };
  },
  computed: {
    scrollH: function () {
      let sys = uni.getSystemInfoSync();
      let winWidth = sys.windowWidth;
      let winrate = 750 / winWidth;
      let bottomHeight = uni.upx2px(100);
      this.bottomHeight = bottomHeight;
      const query = uni.createSelectorQuery().in(this);
      setTimeout(() => {
        query.select(".cu-header").boundingClientRect();
        query.exec((data) => {
          this.paddingT = data[0].height;
        });
      }, 10);
      // #ifdef H5
      let winHeight = parseInt((sys.windowHeight - this.navBarHeight - this.paddingT) * winrate);
      // #endif

      // #ifdef APP-PLUS
      let winHeight = parseInt((sys.windowHeight - (this.inlineTools + this.paddingT + bottomHeight)) * winrate);
      // #endif

      // #ifndef H5 || APP-PLUS
      this.bottomHeight += this.inlineTools;
      // 微信小程序需要减去状态栏+底部导航栏+底部横线
      let winHeight = parseInt((sys.windowHeight - (this.inlineTools + this.paddingT + this.navBarHeight)) * winrate);
      // #endif
      return winHeight;
    },
  },
  watch: {
    newMessage(val) {
      if (val.toContactId == this.contact.id && val.fromUser.id != this.user.user_id) {
        this.$api.msgApi.setMsgIsRead({
          toContactId: this.contact.id,
          is_group: this.contact.is_group,
          messages: val,
          fromUser: val.fromUser.id,
          is_secret: val.is_secret,
        });
      }
      this.scrollToBottom();
    },
    videoModel(val) {
      if (!val) {
        this.video.pause();
      }
    },
    $route(r) {
      if (r.fullPath === "/") {
        clearInterval(this.destructionMsgTimer);
        this.destructionMsgTimer = null;
      }
    },
  },
  onLoad(options) {
    const that = this;
    this.userID = options.id;
    let data = msgStore.getContact(options.id) ?? msgStore.casualUserInfo;
    if (data.is_group == 1 && (data.role < 3 || data.setting.profile == "1")) {
      this.isProfile = true;
    }

    if (data.call_user_ids && JSON.stringify(data.call_user_ids) != "{}") {
      this.ateObj = {
        show: true,
        id: `msg_${data.call_user_ids.msg_id}`,
      };
    }

    this.query = options;
    this.contact = data;
    this.contact_id = options.id;
    this.is_group = data.is_group;
    msgStore.updateContacts({
      id: options.id,
      unread: 0,
    });

    this.is_silent = data.silent ?? 0;

    // 获取屏幕的宽、高
    this.getScreenWH();

    //年龄
    const userInfo = uni.getStorageSync("userInfo") || "{}";
    this.age = uni.getStorageSync("userInfo").age ?? 0;

    //性别
    this.sex = uni.getStorageSync("userInfo").sex ?? 2;

    //获取历史记录
    setTimeout(() => {
      this.getMessageList();
    }, 200);

    console.log(this.contact, "this.contact");

    //焚烧的延时时间
    const secret_time = uni.getStorageSync("userInfo").secret_time ?? 10;
    this.destructionTime = secret_time * 1000;

    uni.$on("updateGroup", (res) => {
      let data = res.data;
      if (res.type === "setManager") {
        this.contact.role = data.role;
      }

      if (res.type === "addGroupUser") {
        this.contact.num++;
      }

      if (res.type === "removeUser") {
        msgStore.deleteContacts({
          id: data.group_id,
        });

        if (this.contact.id === data.group_id) {
          uni.showToast({
            title: "您被移出群聊",
            icon: "none",
          });
          uni.reLaunch({
            url: "/pages/index/index",
          });
        } else {
          this.contact.num--;
        }
      }
    });

    // 监听消息更新请求
    uni.$on("getPositonsOrder", (res) => {
      let message = res.data;
      //更换头像和昵称
      this.changeInfoNum >= 2 && (message["cut"] = true);
      switch (res["type"]) {
        //处理消息已读,将本地的未读消息修改为已读状态
        case "isRead":
          for (let i = 0; message.length > i; i++) {
            const data = {
              id: message[i]["id"],
              is_read: 1,
            };
            this.updateMessage(data);
          }
          break;
        case "silent":
          // this.is_silent = message.is_silent;
          this.contact.silent_me = message.is_silent;

          setTimeout(() => {
            if (message.is_silent == 1) {
              //
              // that.$refs.imInput.changeSilentShow(true)
              //返回
              // this.navBack();
              //隐藏聊天记录，并隐藏通讯录
              // this.changeHide()
            }
          }, 200);

          break;
        case "readAll":
          // 如果某人阅读了消息，全部置为已读
          if (message.toContactId == this.contact.id && this.is_group == 0) {
            this.messageList.forEach((item) => {
              item.is_read = 1;
            });
          }
          break;
        //上线、下线通知
        case "isOnline":
          if (message.id == this.contact.id) {
            this.contact.is_online = message.is_online;
          }
          break;
        // 撤回消息
        case "undoMessage":
          if (
            message.from_user == this.user.user_id &&
            message.isMobile == 1 &&
            getTime() - message.sendTime < 120000
          ) {
            return false;
          }
          this.updateMessage(message);
          break;
        // 群直播状态
        case "live":
          this.contact.live_info = message.status === "live" ? message : 0;
          break;
        case "simple":
        case "group":
        case "webrtc":
        case "tempChat":
          if (message.is_secret == 1) {
            message.readTime = new Date().getTime();
            message.is_read = 1;
            !this.destructionMsgTimer && this.destructionMsg();
          }

          if (message.call_user_ids && message.call_user_ids.length) {
            if (message.call_user_ids.includes(this.userInfo.user_id)) {
              this.ateObj = {
                id: `msg_${message.id}`,
                show: true,
              };
              this.playSound();
            }
          }

          let routes = getCurrentPages();
          let curParam = {};
          // #ifdef MP-WEIXIN
          curParam = routes[routes.length - 1].options ?? "";
          // #endif
          // #ifdef APP-PLUS
          curParam = routes[routes.length - 1].$page.options ?? "";
          // #endif
          // 如果是h5需要单独去获取url的参数
          // #ifdef H5
          let url = location.href;
          curParam = this.$util.parseUrl(url);
          // #endif
          if (message.type == "webrtc") {
            if (!["calling", "hangup", "otherOpt"].includes(message.extends.event)) {
              return false;
            }
            if (message.extends.event == "calling") {
              this.wsData = message;
            }
            let code = parseInt(message.extends.code);
            if ([902, 903, 904, 905, 906, 907].includes(code)) {
              let wsData = this.wsData || message;
              wsData.content = message.content;
              message = wsData;
            }
          }
          let isAppend = false;
          if (message.is_group == 1) {
            if (message.toUser == curParam.id) {
              isAppend = true;
            }
          } else {
            // 如果是当前的聊天房间，才可以进行消息新增
            if (
              message.toContactId == curParam.id ||
              (message.fromUser.id == this.user.user_id && message.toUser == curParam.id)
            ) {
              isAppend = true;
            }
          }

          if (isAppend) {
            msgStore.checkMsg(message);
            msgStore.appendMsg(message);
            msgStore.updateContacts({
              id: curParam.id,
              unread: 0,
            });
          }
          this.scrollToBottom();
          break;
      }
    });
  },
  onUnload() {
    // 聊天记录置为空
    msgStore.msgList = [];
    // 停止所有声音播放
    this.innerAudioContext.stop();
    this.closeMusic();
    this.collectList.length = 0;
    this.choiceCollectShow = false;
    this.curMsg = "";
    this.itemInd = -1;

    uni.$off("updateGroup");
  },
  onHide() {
    this.closeMusic();

    // 停止所有声音播放
    this.innerAudioContext.stop();

    this.choiceCollectShow = false;

    this.curMsg = "";
    this.itemInd = -1;
  },
  // 所有聊天页面都返回首页，避免层级过深
  // onBackPress(options) {
  // 	this.InputBottom = 0
  // 	uni.reLaunch({
  // 		url: "/pages/index/index",
  // 	})
  // 	return true
  // },
  created() {
    const emoji = uni.getStorageSync("emojiList");

    if (!emoji) {
      this.getEmoji();
    } else {
      this.setEmoji(emoji);
    }
  },
  mounted() {
    let paddingB = uni.upx2px(50);
    this.paddingB = paddingB;
    this.footerHeight = 55 + paddingB + "px";

    uni.getSystemInfo({
      success: (res) => {
        this.x = res.windowWidth - 40;
      },
    });
    // 创建视频对象
    this.video = uni.createVideoContext("myVideo", this);
    this.innerAudioContext.onPlay(() => {
      console.log("play准备好了");
    });

    this.innerAudioContext.onTimeUpdate(() => {
      const currentTime = this.innerAudioContext.currentTime ?? 0; // 当前播放时间，单位为秒
      const time = currentTime.toFixed(2);
      this.itemInd != -1 && (this.messageList[this.itemInd].extends.currentTime = time ?? "");
    });

    this.innerAudioContext.onEnded(() => {
      // console.log("播放完毕，继续播放下一个录音！")
      // var cIndex = Number(this.playIndex)
      // for (let i = cIndex + 1; i < this.messageList.length; i++) {
      // 	if (this.messageList[i].type == "voice") {
      // 		this.playNow(this.messageList[i].content, i)
      // 		break
      // 	}
      // }
      // // 如果播放到最后一个,播放结束
      // if (this.messageList.length <= cIndex + 1) {
      // 	this.innerAudioContext.stop()
      // 	this.playIndex = -1
      // }
    });
    this.innerAudioContext.onError((e) => {
      console.log(e);
    });

    //沉默 2
    this.contact.silent == 1 && this.$refs.imInput.changeSilentShow(true);
  },
  onShow() {
    this.newList();
    // 检测ws是否还在线c
    this.socketIo.send({ type: "ping" });

    if (friendStore.cardName.realname) {
      this.$refs.imInput.shareCard(friendStore.cardName.user_id);

      //清空
      setTimeout(() => {
        friendStore.changeCardName({});
      }, 500);
    }
  },
  methods: {
    getEmoji() {
      this.$api.msgApi.emoji().then((res) => {
        if (res.code == 0) {
          uni.setStorageSync("emojiList", res.data);
          this.setEmoji(res.data);
        }
      });
    },
    setEmoji(emoji) {
      // 解析所有表情
      emoji.forEach((item) => {
        if (item.id === 1) {
          item.emoji.forEach((it) => {
            this.emojiMap[it.id] = it.path;
          });
        }
      });
    },
    //编辑图片
    compileImg() {
      this.$refs.chjImgEdit.open({
        // 底图路径
        path: this.curMsg.content,
        // 取消是否有弹窗提示
        isCancelToast: true,
        // 取消弹窗提示内容
        cancelText: "确定真的退出吗?",
        // 确定是否有弹窗提示
        isConfirmToast: true,
        // 确定弹窗提示内容
        confirmText: "决定好了吗?",
        // 设置图标
        iconPath: {
          reset: "@/static/image/rests/shezhi.png",
        },
        // 设置涂鸦图标（根据下标匹配）
        iconPathGraffiti: {
          0: "@/static/image/rests/tuya.png",
        },
      });
    },
    /**
     * H5 环境下将 base64 转成 File 对象
     * @param {String} base64Data  base64字符串，包含 data:* 开头
     * @param {String} fileName    文件名称（例如：upload.jpg）
     * @returns {Promise<File>}    返回一个 Promise，解析为 File 对象
     */
    base64ToFile(base64Data, fileName) {
      return new Promise((resolve, reject) => {
        try {
          // 分离出类型和数据部分
          let arr = base64Data.split(",");
          let mime = arr[0].match(/:(.*?);/)[1];
          let bstr = atob(arr[1]);
          let n = bstr.length;
          let u8arr = new Uint8Array(n);
          while (n--) {
            u8arr[n] = bstr.charCodeAt(n);
          }
          let blob = new Blob([u8arr], { type: mime });
          // 创建 File 对象
          let file = new File([blob], fileName, { type: mime });
          resolve(file);
        } catch (error) {
          reject(error);
        }
      });
    },
    /**
     * 原生 App 环境下通过 plus.io 将 base64 转为本地文件路径
     * @param {String} base64Data  base64字符串，包含 data:* 开头
     * @param {String} fileName    文件名称（例如：upload.jpg）
     * @returns {Promise<String>}  返回一个 Promise，解析为文件的本地路径
     */
    base64ToPath(base64Data, fileName) {
      return new Promise((resolve, reject) => {
        // 请求私有文档目录文件系统
        plus.io.requestFileSystem(
          plus.io.PRIVATE_DOC,
          (fs) => {
            fs.root.getFile(
              fileName,
              { create: true },
              (fileEntry) => {
                fileEntry.createWriter((writer) => {
                  let arr = base64Data.split(",");
                  let mime = arr[0].match(/:(.*?);/)[1];
                  let bstr = atob(arr[1]);
                  let n = bstr.length;
                  let u8arr = new Uint8Array(n);
                  while (n--) {
                    u8arr[n] = bstr.charCodeAt(n);
                  }
                  let blob = new Blob([u8arr], { type: mime });
                  writer.write(blob);
                  writer.onwriteend = () => {
                    // writer 完成写入后返回文件的本地路径
                    resolve(fileEntry.fullPath);
                  };
                  writer.onerror = (e) => {
                    reject(e);
                  };
                });
              },
              (err) => {
                reject(err);
              }
            );
          },
          (err) => {
            reject(err);
          }
        );
      });
    },
    /**
     * 上传 base64 文件数据
     * 根据环境（H5 或 原生 App）选择不同的处理方式
     */
    uploadBase64(base64Str) {
      return new Promise((resolve, reject) => {
        const fileName = "upload.jpg";
        // 如果 plus 对象存在，则认为是在原生 App 环境下
        if (window.plus) {
          // 原生 App 环境：先转换成本地文件，再使用 uni.uploadFile 上传
          this.base64ToPath(base64Str, fileName)
            .then((filePath) => {
              uni.uploadFile({
                url: this.$api.msgApi.uploadImage,
                filePath: filePath,
                name: "file",
                success: (res) => {
                  // 解析服务器返回的数据
                  try {
                    const data = JSON.parse(res.data);
                    console.log("上传成功:", data);
                    resolve(data);
                    // 在此处理返回的数据
                  } catch (e) {
                    console.error("解析服务器返回数据失败:", e);
                  }
                },
                fail: (err) => {
                  reject(err);
                  console.error("上传失败:", err);
                },
              });
            })
            .catch((err) => {
              console.error("文件转换失败:", err);
            });
        } else {
          // H5 环境：转换为 File 对象后使用 FormData + fetch 方式上传
          this.base64ToFile(base64Str, fileName)
            .then((file) => {
              let formData = new FormData();
              formData.append("file", file);
              fetch(this.$api.msgApi.uploadImage, {
                method: "POST",
                body: formData,
                headers: {
                  Authorization: uni.getStorageSync("authToken"),
                },
              })
                .then((response) => response.json())
                .then((data) => {
                  console.log("上传成功:", data);
                  resolve(data);
                  // 在此处理返回的数据
                })
                .catch((err) => {
                  reject(err);
                  console.error("上传失败:", err);
                });
            })
            .catch((err) => {
              console.error("文件转换失败:", err);
            });
        }
      });
    },
    async chjConfirm(path) {
      uni.showActionSheet({
        itemList: ["收藏1", "收藏2", "发送给朋友", "保存图片"],
        success: async (res) => {
          const tapIndex = res.tapIndex;
          if ([0, 1].includes(tapIndex)) {
            const uRes = await this.uploadBase64(path);

            uRes.code == 0 && this.collectMessage(tapIndex, uRes.data);
          } else if (tapIndex == 2) {
            //发送给朋友
            const uRes = await this.uploadBase64(path);

            console.log(uRes, "发送给朋友");

            uni.navigateTo({
              url:
                "/pages/index/userSelection?contact_id=" +
                this.contact_id +
                "&type=4&source=chat&transpond=" +
                uRes.data,
            });
          } else {
            //保存图片
            // #ifdef H5
            uni.showToast({
              title: "仅APP可用",
              icon: "none",
            });
            // #endif
            // #ifdef APP

            let filePath = "";
            const fileName = "upload.jpg";
            filePath = await this.base64ToPath(path, fileName);

            uni.saveImageToPhotosAlbum({
              filePath: filePath,
              success: (s) => {
                uni.showToast({
                  title: "保存成功",
                  icon: "none",
                });
              },
              fail: (e) => {
                uni.showToast({
                  title: `保存成功:${e}`,
                  icon: "none",
                });
              },
            });
            // #endif
          }
        },
        fail: (res) => {
          console.log(res.errMsg);
        },
      });
    },
    chjCancel() {
      console.log("取消");
    },
    gotoATe() {
      const hasId = this.messageList.some((msg) => `msg_${msg.id}` === this.ateObj.id);

      if (hasId) {
        this.scrollIntoView = this.ateObj.id;

        this.$nextTick(() => {
          this.ateObj = {};
        });
      } else {
        setTimeout(() => {
          this.scrolltoupper("ate");
        }, 15);
      }
    },
    playSound() {
      let setting = uni.getStorageSync("appSetting") ?? "";
      if (setting.voiceStatus) {
        let _this = this;
        const innerAudioContext = uni.createInnerAudioContext();
        innerAudioContext.autoplay = true;
        innerAudioContext.src = "https://im-file.jwbl.top/audio/ding.mp3";
        innerAudioContext.onError((res) => {
          uni.showToast({
            title: "有人@你",
            icon: "none",
          });
          //如果音频没有正常播放
        });
        innerAudioContext.onStop((res) => {
          // _this.playing=false
          _this.$forceUpdate();
        });
      }
      if (setting.vibrateStatus) {
        uni.vibrateLong({
          success: function () {
            console.log("手机震动");
          },
        });
      }
    },
    onChange(e) {
      this.x = e.detail.x;
      this.y = e.detail.y;
    },
    toLives() {
      this.$refs.imInput.toLive();
    },

    //查询历史记录
    historyMsg(data) {
      Object.assign(this.historyMsgData, data);
      //先清空之前的信息
      this.clearRecords();
      //重新加载新的
      this.getMessageList();
    },
    newList() {
      //先清空之前的信息
      this.clearRecords();
      //重新加载新的
      this.getMessageList();
      this.scrollToBottom();
    },
    //更新用户信息
    updateContact() {
      //更新用户信息
      let data = msgStore.getContact(this.userID);
      if (data.is_group == 1 && (data.role < 3 || data.setting.profile == "1")) {
        this.isProfile = true;
      }
      this.contact = data;
    },
    //清空记录
    clearRecords() {
      this.messageList.length = 0;
      this.loadLock = false;
      this.page = 1;
      msgList.length = 0;

      this.contact.lastContent = " ";
      msgStore.updateContacts(this.contact);
    },
    //切换对方头像和昵称
    changeInfo(index) {
      this.changeInfoNum = index;
      this.changeInfoShow = false;
      this.$api.msgApi.userinfochange({ user_id: this.contact.id, num: index }).then((res) => {});
    },
    //打开名片的用户信息详情
    openUserDetail(id) {
      uni.navigateTo({
        url: "/pages/contacts/detail?id=" + id,
      });
    },
    //接龙
    joinRelay(item) {
      this.$refs.imInput.startRelay("connect", item.id, item.create_avatar, item.create_user, item.count, item.data);
    },
    //定位信息
    openGetLocation(longitude, latitude) {
      this.$refs.imInput.getLocation(longitude, latitude, false);
    },
    changeSppointDetailShow(index) {
      index > -1 && (this.appointDetailIndex = index);
      this.messageList[this.appointDetailIndex].appointDetail = !!!(
        this.messageList[this.appointDetailIndex].appointDetail ?? false
      );
      this.appointDetailShow = !this.appointDetailShow;
    },
    //条件显示
    conditionShow(destruction, sex, minAge, maxAge, user_id) {
      let show = true;
      if (this.is_group == 1 && !!maxAge) {
        if ((sex == this.sex && !!this.age && minAge < this.age && this.age < maxAge) || user_id == this.user.user_id) {
          show = true;
        } else {
          show = false;
        }
      }

      //焚烧
      if (!!destruction) {
        show = false;
      }

      return show;
    },
    calling(type) {
      this.$refs.imInput.calling(parseInt(type));
    },
    endTimer() {
      clearTimeout(this.timer);
    },
    // 获取屏幕的宽度
    getScreenWH() {
      // 同步获取设备信息
      const systemInfo = uni.getSystemInfoSync();

      // 从系统信息中获取窗口宽度
      this.screenWidth = systemInfo.windowWidth;
      this.screenHeight = systemInfo.windowHeight;
    },
    //单双三击操作
    instructOnClice(e) {
      const _this = this;

      //计算点击的区间位置
      const clientX = e.detail.x;
      const clientY = e.detail.y;
      const sectionW = this.screenWidth / 3;
      const sectionH = this.screenHeight / 3;

      // 划分区域
      const col = Math.floor((clientX / this.screenWidth) * 3); // 列数：0, 1, 2
      const row = Math.floor((clientY / this.screenHeight) * 3); // 行数：0, 1, 2

      // 计算区域编号 (1 ~ 9)
      const zone = row * 3 + col + 1;

      //点击的区域
      if (_this.lastZone !== zone) {
        _this.clickCount = 0;
        _this.lastZone = zone;
      }

      //点击时间
      const curTime = new Date().getTime();
      const lastTime = _this.lastTapDiffTime || 0; // 如果没有上次点击时间，默认0
      _this.lastTapDiffTime = curTime;

      // 计算两次点击之间的时间差
      const diff = curTime - lastTime;

      // 用于存储点击次数
      _this.clickCount++;

      // 超过300ms，重置
      if (lastTime && diff >= 300) {
        _this.clickCount = 0;
        _this.lastZone = 0;
      }

      if (_this.contact.is_group == 1 || _this.contact.is_top === 2) return;

      // 清除之前的定时器
      clearTimeout(_this.clickTimeout);

      // 设置定时器，延迟处理点击逻辑
      _this.clickTimeout = setTimeout(() => {
        switch (_this.clickCount) {
          case 1: // 单击
            // 单击处理 -- 清空聊天记录
            // this.showModals();
            break;
          case 2: // 双击
            if (_this.lastZone === 7) {
              //左 -- 弹窗二次确认，删除聊天记录
              this.showModals();
              break;
            }

            if (_this.lastZone === 8) {
              //中 -- 隐藏聊天记录，并隐藏通讯录
              this.changeHide();

              break;
            }
            if (_this.lastZone === 9) {
              //右 -- 沉默
              this.$refs.imInput.isSilent();
              // this.is_silent == 1
              // 	? uni.showToast({
              // 			title: "请先关闭沉默",
              // 			icon: "none",
              // 	  })
              // 	: this.$refs.imInput.changeSilent(1)
            }

            break;
          case 3: // 三击
            // 三击处理 -- 沉默 - 2版
            // this.$refs.imInput.isSilent();
            break;
          default:
            break;
        }

        // 重置点击计数
        _this.clickCount = 0;

        //重置点击区域
        _this.lastZone = 0;

        _this.lastTapDiffTime = 0;
      }, 300); // 设置300ms的延迟
    },
    //隐藏聊天记录/联系人
    changeHide() {
      this.contact.is_hide = this.contact.is_hide ? 0 : 1;
      msgStore.updateContacts({
        change_hide: true,
        id: this.contact.id,
        is_hide: this.contact.is_hide,
      });

      this.navBack();
    },
    isVip() {
      let status = true;
      // const time = Math.round(new Date().getTime() / 1000);
      // if (time > this.userInfo.member_expire) {
      //   uni.showToast({
      //     title: '当前功能仅限会员可用',
      //     icon: 'none'
      //   });
      //   status = false;
      // }

      return status;
    },
    lModalConfirm() {
      this.modalsStatus === 1 ? this.delFriend() : this.msglogclean();

      this.$nextTick(() => {
        this.lModalCancel();
      });
    },
    lModalCancel() {
      this.showModalDialog = false;
      this.modalsStatus = -1;
    },
    //清空聊天记录 -- 二次确定
    showModals(status) {
      this.modalsStatus = status;
      this.showModalDialog = true;
      // uni.showModal({
      //   title: `删除${status === 1 ? '联系人和' : ''}聊天记录`,
      //   content: `确认是否删除${status === 1 ? '当前联系人和' : ''}聊天记录？`,
      //   success: (res) => {
      //     if (res.cancel) return;
      //     status === 1 ? this.delFriend() : this.msglogclean();
      //   }
      // });
    },
    //确认删除联系人
    delFriend() {
      const data = { id: this.contact.id };
      this.$api.friendApi.delFriend(data).then((res) => {
        if (res.code == 0) {
          msgStore.deleteContacts(data);
          uni.reLaunch({
            url: "/pages/index/index",
          });
        }
      });
    },
    //确认删除记录
    msglogclean() {
      uni.showToast({
        title: "清空中...",
        icon: "loading",
        mask: true,
        duration: 999999,
      });

      const data = {
        is_group: this.contact.is_group,
        toContactId: this.contact_id,
      };

      this.$api.msgApi.msglogclean(data).then((res) => {
        uni.hideToast();
        this.clearRecords(); // 触发上一个页面中的方法

        uni.showToast({
          title: `${res.msg}`,
          icon: "none",
        });
      });
    },
    // 双击
    dblclick(item) {
      const _this = this;
      // 当前时间
      const curTime = new Date().getTime();
      // 上次点击时间
      const lastTime = _this.lastTapDiffTime;
      // 更新上次点击时间
      _this.lastTapDiffTime = curTime;
      // 两次点击间隔小于300ms, 认为是双击
      const diff = curTime - lastTime;
      if (diff < 300) {
        let audioExt = ["mp3", "wav", "acc"];
        let extension = item.content.split(".").pop().toLowerCase();
        if (audioExt.includes(extension) || item.type == "voice") {
          uni.showToast({
            title: "音、视频文件无法预览",
            icon: "none",
          });
          this.curMsg = "";
          this.modelName = "";
          return;
        }

        this.curMsg = item;
        this.modelName = "copyModel";
      }
    },
    quotePreview(item) {
      this.modelName = "copyModel";
      this.curMsg = item;
    },
    getTime() {
      return new Date().getTime();
    },
    //设置指定的底部边距
    assignShowPB(n) {
      this.assignPB = n;
      this.scrollToBottom();
    },
    setPad(padding) {
      //设置聊天内容的地步边距
      this.paddingB = padding;
      this.scrollToBottom();
    },
    updateMessage(message) {
      message.readTime = new Date().getTime();
      !this.destructionMsgTimer && this.destructionMsg();

      let msgList = this.messageList;
      // 更新联系人
      msgList.forEach((item, index) => {
        let msg = msgList[index];
        if (item.id == message.id) {
          msgList[index] = Object.assign(msg, message);
        }
      });
      this.messageList = msgList;
    },
    getScrollHeight() {
      const query = uni.createSelectorQuery().in(this);
      setTimeout(() => {
        query.select(".cu-chat").boundingClientRect();
        query.exec((data) => {
          this.scrollHeight = data[0].height;
          this.scrollTop = data[0].height - this.newheight;
          this.loadLock = false;
        });
      }, 10);
    },
    scrolltoupper(type) {
      //向上的历史记录
      if (this.loadLock == false) {
        this.historyMsgData.order = 1;
        this.loadLock = true;
        this.page++;
        if (this.moreData) {
          this.loading = "loading";
          setTimeout(() => {
            this.getMessageList(type);
          }, 1000);
        }
      }
    },
    scrolltolower() {
      this.historyMsgData.order = 0;
      this.loading = "loading";
      this.getMessageList();
    },
    scrollChat(e) {
      this.newheight = e.detail.scrollHeight;
      if (e.detail.scrollTop < 10 && this.loadLock == false) {
        this.loadLock = true;
        this.page++;
        if (this.moreData) {
          this.loading = "loading";
          setTimeout(() => {
            this.getMessageList();
          }, 1000);
        }
      }
    },
    //焚烧消息
    destructionMsg() {
      // let status = 0;

      this.destructionMsgTimer = setInterval(() => {
        this.messageList.forEach((it, index) => {
          const time = new Date().getTime();

          if (it.is_secret == 1 && it.is_read == 1) {
            // status++;
            if (time > it.readTime + this.destructionTime) {
              // if (time > it.readTime + 3000) {
              !this.destructionMsgTimer && this.destructionMsg();
              it.destruction = true;
              // status--;
            }
          }

          // if (index == this.messageList.length - 1 && status == 0) {
          //   clearInterval(this.destructionMsgTimer);
          // }
        });
      }, this.delayTime);
    },

    getMessageList(types) {
      //this.historyMsgData
      const data = {
        is_group: this.is_group,
        toContactId: this.contact.id,
        limit: this.limit,
      };

      if (this.historyMsgData.type) {
        this.historyMsgData.type === "text"
          ? (data["msg_id"] = this.historyMsgData.msg_id)
          : (data["date"] = this.historyMsgData.date);

        data["order"] = this.historyMsgData.order ?? 0; //1往上翻，0或其他往下
      } else {
        data["page"] = this.page;
      }

      this.$api.msgApi.getMessageList(data).then((res) => {
        if (this.page == 1) {
          msgStore.msgList = [];
        }
        let data = res.data.slice().reverse();

        res.msg &&
          uni.showToast({
            title: `${res.msg}`,
            icon: "none",
          });

        data.forEach((it, index) => {
          const time = new Date().getTime();

          /**
           * it.is_secret == 1 -- 商业密聊
           * time > it.sendTime + this.destructionTime -- 当前时间 > 消息发送时间 + 5分钟
           * 则删除
           */

          if (it.is_secret == 1) {
            it.readTime = new Date().getTime();
            !this.destructionMsgTimer && this.destructionMsg();
          }

          // if (it.is_secret == 1 && it.is_read == 1) {
          //   if (time > it.sendTime + this.destructionTime) {
          //     it.destruction = true;
          //   }
          //   //  else {
          //   //   this.queueList.push({
          //   //     msg_id: it.msg_id,
          //   //     sendTime: it.sendTime
          //   //   });
          //   // }
          // }

          //需要将所有消息都保存，然后根据索引隐藏商业密聊信息
          msgStore.msgList.unshift(it);
        });

        var _this = this;
        this.loading = "more";

        // 如果返回的数据小于每页的数量
        if (res.data.length < this.limit) {
          this.moreData = false;
          this.loading = "noMore";
        }

        this.$nextTick(() => {
          if (this.page == 1) {
            this.scrollToBottom();
          } else {
            this.getScrollHeight();
          }

          if (types == "ate") {
            _this.gotoATe();
          }
        });
      });
    },
    handleRightClick(item, e) {
      // 阻止默认右键菜单
      e.preventDefault();
      // 执行与长按相同的操作
      this.curMsg = JSON.parse(JSON.stringify(item));
      console.log(this.curMsg, "this.curMsg");
      if (item.type == "text") {
        this.copyTxt = "消息";
      } else if (item.type == "image") {
        this.copyTxt = "图片链接";
      } else {
        this.copyTxt = "文件链接";
      }
      this.modelName = "moreOpt";
    },
    moreOption(item) {
      console.log(item, "item");
      this.timer = setTimeout(() => {
        this.curMsg = JSON.parse(JSON.stringify(item));
        console.log(this.curMsg, "this.curMsg");
        if (item.type == "text") {
          this.copyTxt = "消息";
        } else if (item.type == "image") {
          this.copyTxt = "图片链接";
        } else {
          this.copyTxt = "文件链接";
        }
        this.modelName = "moreOpt";
      }, 1000); // 设置为 1 秒
    },
    undoMsg() {
      let message = this.curMsg;
      this.modelName = "";
      this.$api.msgApi.undoMessage({ id: message.id }).then((res) => {
        const data = {
          id: message.id,
          type: "event",
          is_undo: 1,
          content: "你撤回了一条消息",
          oldContent: message.content,
          toContactId: message.toContactId,
        };
        this.updateMessage(data);
      });
    },
    //复制
    copyMsg() {
      uni.setClipboardData({
        data: this.curMsg.content,
        showToast: true,
      });
      this.modelName = "";
      this.curMsg = {};
    },
    //多选 -- 收藏\转发
    choiceMsg() {
      this.choiceCollectShow = !this.choiceCollectShow;
      // this.collectList.length = 0;
    },
    //收藏\转发 -- 多选
    checkboxChange(item) {
      const id = item.msg_id;
      item.checked = item.checked === true ? false : true;

      const index = this.collectList.indexOf(id);

      if (index !== -1) {
        this.collectList.splice(index, 1);
      } else {
        this.collectList.push(id);
      }
    },
    //引用
    quote() {
      this.curMsg.quoteShow = true;
    },
    changeChoiceCollectShow() {
      this.choiceCollectShow = !this.choiceCollectShow;
      this.collectList.length = 0;
    },
    //删除
    removeMessage(id) {
      if (id === 1) {
        this.collectList.push(this.curMsg.msg_id);
      } else {
        this.collectList.sort((a, b) => a - b);
      }

      uni.showModal({
        title: "删除记录",
        content: "确认删除记录？",
        success: (res) => {
          if (res.cancel) {
            this.collectList.length = 0;
            return;
          }

          this.$api.msgApi.removeMessage({ id: this.collectList }).then((res) => {
            if (res.code != 0) return;

            for (let i = this.messageList.length - 1; i >= 0; i--) {
              if (this.collectList.includes(this.messageList[i].msg_id)) {
                this.messageList.splice(i, 1);
              }
            }
          });
        },
      });
    },
    //收藏
    collectMsg(id) {
      // if (!this.isVip()) return;

      if (id === 1) {
        this.collectList.push(this.curMsg.msg_id);
      } else {
        this.collectList.sort((a, b) => a - b);
      }

      const itemList = ["收藏1", "收藏2"];
      this.curMsg.type === "emoji-image" && itemList.push("表情包");

      uni.showActionSheet({
        title: "收藏到",
        itemList: itemList,
        success: (res) => {
          const tapIndex = res.tapIndex;
          const params = {
            channel: tapIndex,
          };

          if (tapIndex === 2) {
            params["content"] = {
              type: "image",
              content: this.curMsg.content,
            };
          } else {
            params["msg_id"] = this.collectList.join(",");
          }

          this.$api.msgApi
            .collectMessage(params)
            .then((res) => {
              if (res.code == 0) {
                this.collectList.length = 0;
                this.choiceCollectShow = false;

                uni.showToast({
                  title: res.msg || "收藏成功",
                  icon: "none",
                });
              } else {
                uni.showToast({
                  title: res.msg || "收藏失败",
                  icon: "none",
                });
              }
            })
            .catch((err) => {
              uni.showToast({
                title: "收藏失败",
                icon: "none",
              });
              console.log(err, "失败");
            });
        },
        fail: (res) => {
          console.log(res.errMsg);
        },
      });
    },
    //收藏API
    collectMessage(index, url) {
      this.$api.msgApi
        .collectMessage({
          content: {
            type: "image",
            content: url,
          },
          channel: index,
        })
        .then((res) => {
          if (res.code == 0) {
            uni.showToast({
              title: res.msg || "收藏成功",
              icon: "none",
            });
          } else {
            uni.showToast({
              title: res.msg || "收藏失败",
              icon: "none",
            });
          }
        })
        .catch((err) => {
          uni.showToast({
            title: "收藏失败",
            icon: "none",
          });
          console.log(err, "失败");
        });
    },
    // 转发消息
    forwardMsg(type) {
      if (type == 2) {
        this.curMsg.type_transpond = 2;
        this.curMsg.msg_id = this.collectList;
      }

      // this.choiceCollectShow = false;

      uni.navigateTo({
        url: "/pages/index/userSelection?contact_id=" + this.contact_id + "&type=3&source=chat",
      });
    },
    reEdit(text) {
      this.$refs.imInput.inputMsg = text;
      this.$refs.imInput.isFocus = true;
    },
    // 滚动到页面底部
    scrollToBottom() {
      const query = uni.createSelectorQuery().in(this);
      setTimeout(() => {
        query.select(".cu-chat").boundingClientRect();
        query.exec((data) => {
          let height = data[0] ? data[0].height ?? 999999 : 999999;
          this.scrollTop = height + 3000;
        });
      }, 10);
    },
    // 打开聊天详情
    openDetails() {
      // if (!this.noviceGuide.includes(30)) {
      //   this.noviceGuide.push(30);
      //   uni.setStorageSync('noviceGuide', this.noviceGuide);
      // }
      uni.navigateTo({
        url: "/pages/message/detail?id=" + this.contact.id + "&is_group=" + this.contact.is_group,
      });
    },
    fileSize(size) {
      return this.$util.getFileSize(size);
    },
    // 自动解析消息中的表情
    emojiToHtml(str) {
      return str.replace(/\[!(\w+)\]/gi, (str, match) => {
        var file = match;
        return this.emojiMap[file]
          ? '<img class=\'mr-5 emo-img\' style="width:18px;height:18px" emoji-name="'
              .concat(match, '" src="')
              .concat(this.emojiMap[file], '" />')
          : "[!".concat(match, "]");
      });
    },
    // 重新发送
    reSend(message) {
      message.status = "going";
      this.sendMessage(JSON.parse(JSON.stringify(message)), "");
    },
    //沉默
    isSilent(type) {
      this.is_silent = Number(type);
    },
    // 发送消息
    sendMessage(message, file, isSecret) {
      if (this.contact.silent_me == 1) {
        uni.showToast({
          title: "对方已开启沉默",
          icon: "none",
        });
        return;
      }
      if (this.contact.silent == 1) {
        uni.showToast({
          title: "已开启沉默",
          icon: "none",
        });
        return;
      }
      // 如果开启了群聊禁言或者关闭了单聊权限，就不允许发送消息
      if ((!this.globalConfig.chatInfo.simpleChat && this.is_group == 0) || !this.nospeak()) {
        //已开启禁言
        uni.showToast({
          title: "系统已关闭单聊，或者群已开启禁言，无法发送消息",
          icon: "none",
        });
        return;
      }

      let user = this.user;
      user.id = user.user_id;
      message.fromUser = user;
      message.from_user = this.user.user_id;
      message.toContactId = this.contact.id;
      message.is_group = this.contact.is_group;

      //商业密聊
      message["is_secret"] = isSecret;
      message.is_secret = isSecret;

      //临时聊天
      this.contact.tempChat && (message["group_id"] = this.contact.group_id);

      //引用
      if (this.curMsg.quoteShow) {
        message["quote"] = {
          name: this.curMsg.fromUser.realname,
          content: this.curMsg.content,
        };
      }

      this.messageList.push(message);
      this.scrollToBottom();

      let msgObj = {};
      Object.assign(msgObj, message);

      var fileTypes = ["image", "file", "video", "voice"];

      if (["text", "usercard", "location", "connectdragon", "emoji-image"].includes(message.type)) {
        this.$api.msgApi
          .sendMessage(msgObj)
          .then((res) => {
            this.curMsg = "";
            if (res.code == 0) {
              this.updateMessage(res.data);
            } else if (res.code == 401) {
              // 删除最后一条信息
              this.messageList.pop();
              //已开启禁言
              uni.showToast({
                title: res.msg,
                icon: "none",
              });
            } else if (res.code == 400) {
              //沉默
              // 删除最后一条信息
              this.messageList.pop();
            } else {
              uni.showToast({
                title: `${res.msg}`,
                icon: "none",
              });
            }
          })
          .catch((error) => {
            this.sendFailed(message);
          });
      } else if (fileTypes.includes(message.type)) {
        var self = this;
        if (message.fileSize > 10240000) {
          return uni.showToast({
            title: "文件大小不能超过10M",
            icon: "error",
          });
        }
        uni.uploadFile({
          url: this.$api.msgApi.uploadUrl,
          filePath: message.content,
          name: "file",
          header: {
            Authorization: uni.getStorageSync("authToken"),
          },
          formData: {
            message: JSON.stringify(message),
          },
          success: (e) => {
            let res = JSON.parse(e.data);

            if (res.code == 0) {
              this.updateMessage(res.data);
            } else if (res.code == 401) {
              // 删除最后一条信息
              this.messageList.pop();
              //已开启禁言
              uni.showToast({
                title: res.msg,
                icon: "none",
              });
            }
          },
          fail: (res) => {
            this.sendFailed(message);
          },
        });
      }
    },
    sendFailed(message) {
      message.status = "failed";
      this.updateMessage(JSON.parse(JSON.stringify(message)));
    },
    closeModel() {
      this.videoUrl = "";
      this.videoModel = false;
    },
    // 播放视频,禁止多个同时播放
    handlePlay(item) {
      this.videoUrl = item.content;
      this.videoModel = true;
      this.innerAudioContext.stop();
      this.playIndex = -1;
    },
    sendTime: function (mstime) {
      return this.$util.timeFormat(mstime);
    },
    // 播放语音
    playVoice: function (e, itemInd) {
      // this.innerAudioContext = uni.createInnerAudioContext();
      var voicelUrl = e.currentTarget.dataset.voice;
      var index = e.currentTarget.dataset.index;
      this.itemInd = itemInd;

      if (this.playIndex == -1) {
        return this.playNow(voicelUrl, index);
      }
      if (this.playIndex == index) {
        this.innerAudioContext.stop();
        this.playIndex = -1;
      } else {
        this.innerAudioContext.stop();
        this.playIndex = -1;

        this.playNow(voicelUrl, index);
      }
    },
    // 语音播放基础函数
    playNow: function (voicelUrl, index) {
      this.playIndex = index;
      this.innerAudioContext.autoplay = true;
      // #ifdef H5
      // this.innerAudioContext.obeyMuteSwitch = false
      // #endif
      this.innerAudioContext.src = voicelUrl;

      this.innerAudioContext.play();

      return true;
    },
    // 文件预览
    preview(item) {
      let audioExt = ["mp3", "wav", "acc"];
      let extension = item.content.split(".").pop().toLowerCase();
      if (audioExt.includes(extension)) {
        uni.showToast({
          title: "音频文件无法预览",
          icon: "exception",
        });
        // this.curMsg = item;
        // this.modelName = 'musicPlay';
        return;
      }
      // #ifdef APP-PLUS || MP-WEIXIN
      let exts = ["doc", "xls", "ppt", "pdf", "docx", "xlsx", "pptx"];
      if (exts.includes(extension)) {
        uni.showLoading({ title: "文件加载中" });
        uni.downloadFile({
          url: item.content,
          success: function (res) {
            uni.hideLoading();
            var filePath = res.tempFilePath;
            uni.openDocument({
              filePath: filePath,
              showMenu: true,
              success: function (res) {
                console.log("打开文档成功");
              },
            });
          },
          fail() {
            uni.hideLoading();
          },
        });
      } else {
        uni.showToast({
          title: "该文件不支持预览！",
          icon: "none",
        });
      }
      // #endif

      // #ifdef H5
      const tempLink = document.createElement("a");
      tempLink.style.display = "none";
      tempLink.href = item.download;
      tempLink.setAttribute("download", item.fileName);
      tempLink.setAttribute("target", "_blank");
      document.body.appendChild(tempLink);
      tempLink.click();
      document.body.removeChild(tempLink);
      // #endif
    },
    closeMusic() {
      this.modelName = "";
      this.$refs.audio.audioPause();
    },
    // 图片预览
    showImgs: function (e) {
      var imgs = [];
      var imgsCurrent = e.currentTarget.dataset.img;
      for (var i = 0; i < this.messageList.length; i++) {
        if (this.messageList[i].type == "image") {
          imgs.push(this.messageList[i].content);
        }
      }
      uni.previewImage({ urls: imgs, current: imgsCurrent });
    },
    // 如果点击了聊天记录列表页,需要收起表情面板或者其他的面板
    closeInput(e) {
      this.boxStatus++;
    },
    // 禁言时禁止发送消息
    nospeak() {
      if (this.is_group == 1 && this.contact.setting.nospeak > 0) {
        if (this.contact.setting.nospeak == 1 && [1, 2].includes(this.contact.role)) {
          return true;
        } else if (this.contact.setting.nospeak == 2 && this.contact.role == 1) {
          return true;
        } else {
          return false;
        }
      } else {
        return true;
      }
    },
  },
};
</script>

<style lang="scss">
page {
  padding-bottom: 100upx;
}
scroll-view {
  width: 100%;
}
.novice-guide-location-2 {
  position: relative;
  z-index: 999 !important;
  background-color: rgba(0, 0, 0, 0) !important;
  pointer-events: none;
}
.appoint-detail-overlay {
  position: fixed;
  z-index: 203;
  top: var(--status-bar-height);
  left: 0;
  right: 0;
  bottom: 0;
  background-color: rgba(0, 0, 0, 0.7);
}

.appoint-detail {
  position: absolute;
  top: -160rpx;
  z-index: 204;
  transition: transform 0.3s;
  padding: 22rpx;
  background: #f2f2f2;
  border-radius: 16rpx 16rpx 16rpx 0rpx;
  line-height: 2em;
  font-weight: 600;
  font-size: 34rpx;
  color: #000000;

  .appoint-detail-li {
    width: auto;
    display: flex;
    flex-wrap: nowrap;

    .appoint-detail-decoration {
      margin-right: 10rpx;
    }
  }
}

.padding-tb-sm-2 {
  display: flex;
  justify-content: center;
  align-items: center;
}

.select-collect-wrap {
  position: fixed;
  bottom: 0;
  left: 0;
  z-index: 200;
  width: 750rpx;
  display: flex;
  justify-content: space-around;
  align-items: center;
  background-color: #fff;
  box-shadow: 0 2rpx 16rpx #ccc;
  height: 100rpx;

  .select-collect-btn__text {
    flex: 1;
    height: 100rpx;
    line-height: 100rpx;
    text-align: center;
    border-right: 1rpx solid #eee;
  }

  .select-collect-btn {
    width: 80rpx;
    padding: 20rpx;
  }

  .select-collect-btn-2 {
    color: red;
  }
}
.cu-chat {
  min-height: calc(100% - 300px);
}
//禁言
.banned-chat {
  position: absolute;
  padding-bottom: 0px;
  bottom: 0px;
  left: 0;
  background: #f4f5f6;
  z-index: 101;
  width: 100%;
  height: 3rem;
  box-shadow: 1px 1px 6px #999999;
  text-align: center;
  line-height: 3rem;
}
//收藏的多选
.cu-item .collect-checkbox {
  height: 2.5rem;
  flex-shrink: 0;
  margin: 0;
  margin-right: 10rpx;
  display: flex;
  align-items: center;
}

.scroll-wrap {
  width: 100%;
  height: calc(100vh - v-bing(footerHeight));
  padding-top: 45px;
}

.im-rows-reverse .collect-checkbox {
  position: absolute;
  left: 20rpx;
  // margin: 0;
  // margin-left: 10rpx;
}
.icon-png-2 {
  padding: 10rpx;
}
//标记
.mark-wrap {
  position: relative;
  font-family: -apple-system-font, Helvetica Neue, Arial, sans-serif;
  min-width: 50rpx;
  font-size: 24rpx;
  height: 1.5em;
  line-height: 1.4em;
  text-align: center;
  font-weight: 400;
  color: #1a66ff;
  background: #ffffff;
  border-radius: 999rpx;
  border: 2rpx solid #1a66ff;
  // display: flex;
  // flex-direction: row;
  // align-items: center;
  padding: 0rpx 8rpx;
}

//商业密聊 -- 标记
.cu-item .mark-wrap {
  left: -8rpx;
}
.im-rows-reverse .mark-wrap {
  right: -8rpx;
  left: auto;
}
//指定信息
.appoint-wrap {
  position: relative;
  left: 5em;
  top: -0.8em;
  font-weight: 400;
  font-size: 22rpx;
  color: #1a66ff;
}
.cu-chat .cu-item.self {
  justify-content: flex-start;
  text-align: right;
}
.im {
  padding: 30rpx;
}
.im-system-msg {
  color: #ffffff;
  font-size: 26rpx;
  line-height: 38rpx;
  padding: 5px 10px;
  display: block;
  border-radius: 6rpx;
}
.im-msg {
  margin-bottom: 28px;
  display: flex;
  flex-direction: row;
  flex-wrap: nowrap;
}
.im-voice-msg {
  height: 80rpx;
  padding: 0 20rpx;
  background-color: #e7f0f3;
  color: #2b2e3d;
  min-width: 160rpx;
  // max-width: 240rpx;
}

.play-time {
  padding: 0 20rpx;
  color: #999;
  flex-shrink: 0;
}
.linear-green .play-time {
  color: #ffffffb3;
}
.extends-duration {
  display: flex;
  align-items: center;
  flex-shrink: 0;
}

.im-voice-msg-text {
  font-size: calc(var(--amplified_base) * 22rpx);
  margin: 0 5rpx;
  display: flex;
  align-items: center;
}
.cu-chat .cu-item {
  // padding: 30upx 30upx 70upx;
  position: relative;
  padding-left: 19rpx;
  padding-right: 19rpx;
  margin-top: 12rpx;
}
.cu-chat .cu-item > .main {
  max-width: calc(100% - 230rpx);
  margin: 0 0 0 30rpx;
  display: flex;
  align-items: flex-start;
}

.cu-chat .im-rows-reverse > .im-wrap {
  margin: 0 30rpx 0 0;
}
.course-video {
  width: 240rpx;
  height: 240rpx;
  overflow: hidden;
  position: relative;
}

.video-model {
  background-color: #3838388f;
  z-index: 10000;
  width: 100%;
  height: 100%;
  position: fixed;
  top: var(--status-bar-height);
  overflow: hidden;
}
.close-model {
  position: absolute;
  top: 180rpx;
  right: 20rpx;
  background-color: #3838388f;
  padding: 4rpx 10rpx;
}
.video-box {
  width: 100%;
}
.icon-center {
  position: absolute;
  top: 50%;
  z-index: 4;
  transform: translate(-50%, -50%);
  left: 50%;
  padding: 0 4rpx 0 6rpx;
}
.relative-shadow {
  position: absolute;
  width: 100%;
  height: 100%;
  background: #83838387;
  z-index: 1;
}
.file-card {
  width: 420rpx;
  height: 120rpx;
  .file-icon {
    width: 60rpx;
    height: 80rpx;
  }
  .file-name {
    text-align: left !important;
    width: 300rpx;
  }
  .file-size {
    text-align: left !important;
    margin-top: 8rpx;
  }
}

.icon-spin {
  animation: spin 1s linear infinite;
}
@keyframes spin {
  to {
    transform: rotate(360deg);
  }
}

.main .content ::v-deep uni-text,
.main .content ::v-deep uni-text span {
  word-wrap: break-word !important;
}

.text-container {
  -webkit-user-select: text !important;
  user-select: text !important;
  font-size: 48rpx;
  word-wrap: break-word !important;
  text-align: left;
  line-height: 1.5;
  letter-spacing: 1.2px;
  color: #333;
}

.cu-chat {
  min-height: 100%;
  // background-color: #e6e6e6;
}

.emo-img {
  display: inline-block;
}

//名片
.user-card {
  display: flex;
  flex-direction: column;
  min-width: 250rpx;
  background-color: #fff !important;

  .card-top {
    padding: 20rpx;
    display: flex;
    flex-direction: row;
    align-items: center;

    .card-avatar {
      width: 80rpx;
      height: 80rpx;
      border-radius: 8rpx;
    }

    .card-realname {
      font-weight: bold;
      font-size: 30rpx;
      margin-left: 12rpx;
      min-width: 8em;
    }
  }

  .card-bottom {
    width: 100%;
    padding: 4rpx 20rpx;
    font-size: 20rpx;
    color: #aaaaaa;
    border-top: 1rpx solid #f4f4f4;
  }
}

//定位
.user-location {
  flex-direction: column;
  background-color: #fff;
  padding: 0 !important;

  .user-location-top {
    padding: 10rpx 20rpx;
    font-weight: bold;
    color: #333;

    .user-location-township {
      color: #a5a5a5;
      font-size: 16rpx;
    }
  }

  .user-location-map {
    width: 100%;
    pointer-events: none;
  }
}

//引用回复
.item-quote-wrap {
  background-color: #ccc;
  padding: 4rpx 10rpx;
  margin-top: 10rpx;
  border-radius: 8rpx;
}

//接龙
.user-relay {
  position: relative;
  display: flex !important;
  flex-direction: column !important;
  align-items: flex-start !important;
  text-align: left !important;
  padding: 20rpx !important;

  .user-relay__title {
    color: #1a66ff;
  }

  .user-relay__list {
    margin-top: 30rpx;

    .user-relay__list-item {
      word-break: break-all;
      line-height: 1.2;
      margin-top: 12rpx;
    }
  }

  .user-relay__desc {
    margin-top: 30rpx;
  }

  .user-relay__join {
    position: absolute;
    bottom: -60rpx;
    left: 0;
    width: 6em;
    height: 40rpx;
    text-align: center;
    background-color: #ccc;
    color: #fff;
    line-height: 42rpx;
    font-size: 20rpx;
    letter-spacing: 1px;
    border-radius: 4rpx;
  }
}

.user-info-overlay {
  z-index: 101 !important;
}
:deep .change-user-info-popup {
  display: flex;
  flex-direction: column;

  .change-user-info-item {
    display: flex;
    flex-direction: row;
    align-items: center;
    justify-content: center;
    padding: 32rpx 0;
  }

  .change-user-info-avatar {
    width: 64rpx;
    height: 64rpx;
    border-radius: 36rpx 36rpx 36rpx 36rpx;
    margin-right: 16rpx;
  }
}

.movable-area-box {
  width: 100vw;
  height: 100vh;
  position: fixed;
  z-index: 1000;
  pointer-events: none;

  .movable-view-box {
    pointer-events: auto;
    width: 100rpx;
    height: 100rpx;
    box-shadow: 2px 2px 8px #ccc;
    line-height: 1.2;
    background-color: #1989fa;
    display: flex;
    flex-direction: column;
    justify-content: center;
    align-items: center;
    font-size: 24rpx;
    border-radius: 50%;
    color: #fff;
  }
}
.l-dialog-overlay {
  position: fixed;
  top: var(--status-bar-height);
  left: 0;
  right: 0;
  bottom: 0;
  z-index: 151;
  background-color: rgba(0, 0, 0, 0.7);
}
.l-dialog {
  position: fixed;
  background-color: #fff;
  z-index: 152;
  width: 600rpx;
  padding: 0;
  top: 75%;
  left: 50%;
  transform: translate(-50%, -50%);
  border: none;
  border: 1rpx solid #ccc;
  border-radius: 12rpx;
  font-size: 32rpx;
  text-align: center;

  .l-dialog-title {
    font-size: 40rpx;
    line-height: 1.5;
    padding-top: 40rpx;
  }

  .l-dialog-content {
    margin-top: 40rpx;
  }

  .l-dialog-btns {
    margin-top: 40rpx;
    display: flex;
    justify-content: space-between;
    align-items: center;
    border-top: 1rpx solid #f4f4f4;
    font-size: 34rpx;
    letter-spacing: 2rpx;

    .l-dialog-btn {
      flex: 1;
      padding: 40rpx 0;
      height: 100%;
    }

    .l-dialog-btn__confirm {
      color: #1a66ff;
      border-right: 1rpx solid #f4f4f4;
    }
  }
}
.item-level__wrap {
  display: flex;
  align-items: center;
}

.level-icon-wrap {
  display: flex;
  align-items: center;
  color: #22436d;
  font-size: 24rpx;
  margin-left: 15rpx;

  .level-icon {
    width: 40rpx !important;
  }
}
.level-icon__1 {
  width: 40rpx !important;
  margin-left: 12rpx;
}

.ate-tag {
  position: fixed;
  top: calc(20vh + var(--status-bar-height));
  right: 0;
  border-radius: 999px 0 0 999px;
  padding: 16rpx 24rpx;
  background-color: #fff;
  color: #2d2dff;
}
</style>
